/**
 * https://codegolf.stackexchange.com/questions/35569/tweetable-mathematical-art
 * */
#pragma once
#include <omp.h>

#include <cmath>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <thread>
#include <vector>

#define DIM 1024
#define DM1 (DIM - 1)
#define _sq(x) ((x) * (x))                           // square
#define _cb(x) abs((x) * (x) * (x))                  // absolute value of cube
#define _cr(x) (unsigned char)(pow((x), 1.0 / 3.0))  // cube root

class painter
{
   public:
    virtual const char *NAME() = 0;
    virtual unsigned char RD(int i, int j) = 0;
    virtual unsigned char GR(int i, int j) = 0;
    virtual unsigned char BL(int i, int j) = 0;
};
/************************************ Table Cloths ************************************/
class Table_Cloths_Flat : public painter
{
    virtual const char *NAME()
    {
        return "Table_Cloths_Flat";
    }

    unsigned char RD(int i, int j)
    {
        float s = 3. / (j + 99);
        return (int((i + DIM) * s + j * s) % 2 + int((DIM * 2 - i) * s + j * s) % 2) * 127;
    }
    unsigned char GR(int i, int j)
    {
        float s = 3. / (j + 99);
        return (int((i + DIM) * s + j * s) % 2 + int((DIM * 2 - i) * s + j * s) % 2) * 127;
    }
    unsigned char BL(int i, int j)
    {
        float s = 3. / (j + 99);
        return (int((i + DIM) * s + j * s) % 2 + int((DIM * 2 - i) * s + j * s) % 2) * 127;
    }
};

class Table_Cloths_Ripple : public painter
{
    virtual const char *NAME()
    {
        return "Table_Cloths_Ripple";
    }

    unsigned char RD(int i, int j)
    {
        float s = 3. / (j + 99);
        float y = (j + sin((i * i + _sq(j - 700) * 5) / 100. / DIM) * 35) * s;
        return (int((i + DIM) * s + y) % 2 + int((DIM * 2 - i) * s + y) % 2) * 127;
    }
    unsigned char GR(int i, int j)
    {
        float s = 3. / (j + 99);
        float y = (j + sin((i * i + _sq(j - 700) * 5) / 100. / DIM) * 35) * s;
        return (int((i + DIM) * s + y) % 2 + int((DIM * 2 - i) * s + y) % 2) * 127;
    }
    unsigned char BL(int i, int j)
    {
        float s = 3. / (j + 99);
        float y = (j + sin((i * i + _sq(j - 700) * 5) / 100. / DIM) * 35) * s;
        return (int((i + DIM) * s + y) % 2 + int((DIM * 2 - i) * s + y) % 2) * 127;
    }
};

class Table_Cloths_Colour : public painter
{
    virtual const char *NAME()
    {
        return "Table_Cloths_Colour";
    }

    unsigned char RD(int i, int j)
    {
        float s = 3. / (j + 99);
        float y = (j + sin((i * i + _sq(j - 700) * 5) / 100. / DIM) * 35) * s;
        return (int((i + DIM) * s + y) % 2 + int((DIM * 2 - i) * s + y) % 2) * 127;
    }
    unsigned char GR(int i, int j)
    {
        float s = 3. / (j + 99);
        float y = (j + sin((i * i + _sq(j - 700) * 5) / 100. / DIM) * 35) * s;
        return (int(5 * ((i + DIM) * s + y)) % 2 + int(5 * ((DIM * 2 - i) * s + y)) % 2) * 127;
    }
    unsigned char BL(int i, int j)
    {
        float s = 3. / (j + 99);
        float y = (j + sin((i * i + _sq(j - 700) * 5) / 100. / DIM) * 35) * s;
        return (int(29 * ((i + DIM) * s + y)) % 2 + int(29 * ((DIM * 2 - i) * s + y)) % 2) * 127;
    }
};

class Table_Cloths_motion : public painter
{
    virtual const char *NAME()
    {
        return "Table_Cloths_motion";
    }

    unsigned char RD(int i, int j)
    {
#define P 6.03
        float s = 3. / (j + 250), y = (j + sin((i * i + _sq(j - 700) * 5) / 100. / DIM + P) * 15) * s;
        return (int((i + DIM) * s + y) % 2 + int((DIM * 2 - i) * s + y) % 2) * 127;
    }

    unsigned char GR(int i, int j)
    {
        float s = 3. / (j + 250);
        float y = (j + sin((i * i + _sq(j - 700) * 5) / 100. / DIM + P) * 15) * s;
        return (int(5 * ((i + DIM) * s + y)) % 2 + int(5 * ((DIM * 2 - i) * s + y)) % 2) * 127;
    }

    unsigned char BL(int i, int j)
    {
        float s = 3. / (j + 250);
        float y = (j + sin((i * i + _sq(j - 700) * 5) / 100. / DIM + P) * 15) * s;
        return (int(29 * ((i + DIM) * s + y)) % 2 + int(29 * ((DIM * 2 - i) * s + y)) % 2) * 127;
    }
};

/************************************ Random ************************************/

class Random : public painter
{
    virtual const char *NAME()
    {
        return "Random";
    }
    // static char c[1024][1024];
    // return !c[i][j] ? c[i][j] = r(999) ? RD((i + r(5) + 1022) % 1024, (j + r(5) + 1022) % 1024) : r(256) : c[i][j];

    unsigned char RD(int i, int j)
    {
#define r(n) (rand() % n)
        static char c[1024][1024];
        return !c[i][j] ? c[i][j] = !r(999) ? r(256) : RD((i + r(2)) % 1024, (j + r(2)) % 1024) : c[i][j];
    }
    unsigned char GR(int i, int j)
    {
        static char c[1024][1024];
        return !c[i][j] ? c[i][j] = !r(999) ? r(256) : GR((i + r(2)) % 1024, (j + r(2)) % 1024) : c[i][j];
    }
    unsigned char BL(int i, int j)
    {
        static char c[1024][1024];
        return !c[i][j] ? c[i][j] = !r(999) ? r(256) : BL((i + r(2)) % 1024, (j + r(2)) % 1024) : c[i][j];
    }
};

/************************************ swirly ************************************/
class Swirly_1 : public painter
{
    virtual const char *NAME()
    {
        return "Swirly_1";
    }
    unsigned char RD(int i, int j)
    {
        return (sqrt(_sq(73. - i) + _sq(609 - j)) + 1) / (sqrt(abs(sin((sqrt(_sq(860. - i) + _sq(162 - j))) / 115.0))) + 1) / 200;
    }
    unsigned char GR(int i, int j)
    {
        return (sqrt(_sq(160. - i) + _sq(60 - j)) + 1) / (sqrt(abs(sin((sqrt(_sq(86. - i) + _sq(860 - j))) / 115.0))) + 1) / 200;
    }
    unsigned char BL(int i, int j)
    {
        return (sqrt(_sq(844. - i) + _sq(200 - j)) + 1) / (sqrt(abs(sin((sqrt(_sq(250. - i) + _sq(20 - j))) / 115.0))) + 1) / 200;
    }
};

class Swirly_2 : public painter
{
    virtual const char *NAME()
    {
        return "Swirly_2";
    }
    unsigned char RD(int i, int j)
    {
        return (sqrt(_sq(148. - i) + _sq(1000 - j)) + 1) / (sqrt(abs(sin((sqrt(_sq(500. - i) + _sq(400 - j))) / 115.0))) + 1) / 200;
    }
    unsigned char GR(int i, int j)
    {
        return (sqrt(_sq(610. - i) + _sq(60 - j)) + 1) / (sqrt(abs(sin((sqrt(_sq(864. - i) + _sq(860 - j))) / 115.0))) + 1) / 200;
    }
    unsigned char BL(int i, int j)
    {
        return (sqrt(_sq(180. - i) + _sq(100 - j)) + 1) / (sqrt(abs(sin((sqrt(_sq(503. - i) + _sq(103 - j))) / 115.0))) + 1) / 200;
    }
};

/************************************ Mandelbrot ************************************/

class Mandelbrot_3_133 : public painter
{
    virtual const char *NAME()
    {
        return "Mandelbrot_3_133";
    }
    unsigned char RD(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + j * 8e-9 - .645411;
            a = c - d + i * 8e-9 + .356888;
        }
        return 255 * pow((n - 80) / 800, 3.);
    }
    unsigned char GR(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + j * 8e-9 - .645411;
            a = c - d + i * 8e-9 + .356888;
        }
        return 255 * pow((n - 80) / 800, .7);
    }
    unsigned char BL(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + j * 8e-9 - .645411;
            a = c - d + i * 8e-9 + .356888;
        }
        return 255 * pow((n - 80) / 800, .5);
    }
};

class Mandelbrot_132 : public painter
{
    virtual const char *NAME()
    {
        return "Mandelbrot_132";
    }
    unsigned char RD(int i, int j)
    {
        double a = 0, b = 0, d, n = 0;
        for (; a * a + (d = b * b) < 4 && n++ < 8192; b = 2 * a * b + j / 5e4 + .06, a = a * a - d + i / 5e4 + .34)
            ;
        return n / 4;
    }
    unsigned char GR(int i, int j)
    {
        return 2 * RD(i, j);
    }
    unsigned char BL(int i, int j)
    {
        return 4 * RD(i, j);
    }
};

class Mandelbrot__1 : public painter
{
    virtual const char *NAME()
    {
        return "Mandelbrot__1";
    }
    unsigned char RD(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + (j)*9e-9 - .645411;
            a = c - d + (i)*9e-9 + .356888;
        }
        return 1000 * pow((n) / 800, .5);
    }
    unsigned char GR(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + (j)*9e-9 - .645411;
            a = c - d + (i)*9e-9 + .356888;
        }
        return 8000 * pow((n) / 800, .5);
    }
    unsigned char BL(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + (j)*9e-9 - .645411;
            a = c - d + (i)*9e-9 + .356888;
        }
        return 8000 * pow((n) / 800, .5);
    }
};

class Mandelbrot__1_1 : public painter
{
    virtual const char *NAME()
    {
        return "Mandelbrot__1_1";
    }
    unsigned char RD(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + (j)*9e-9 - .645411;
            a = c - d + (i)*9e-9 + .356888;
        }
        return 8000 * pow((n) / 800, .5);
    }
    unsigned char GR(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + (j)*9e-9 - .645411;
            a = c - d + (i)*9e-9 + .356888;
        }
        return 40 * pow((n) / 800, .5);
    }
    unsigned char BL(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + (j)*9e-9 - .645411;
            a = c - d + (i)*9e-9 + .356888;
        }
        return 10 * pow((n) / 800, .5);
    }
};

class Mandelbrot__2 : public painter
{
    virtual const char *NAME()
    {
        return "Mandelbrot__2";
    }
    unsigned char RD(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + j * 8e-8 - .645411;
            a = c - d + i * 8e-8 + .356888;
        }
        return 2000 * pow((n) / 800, .5);
    }
    unsigned char GR(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + j * 8e-8 - .645411;
            a = c - d + i * 8e-8 + .356888;
        }
        return 1000 * pow((n) / 800, .5);
    }
    unsigned char BL(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + j * 8e-8 - .645411;
            a = c - d + i * 8e-8 + .356888;
        }
        return 4000 * pow((n) / 800, .5);
    }
};

class Mandelbrot__3 : public painter
{
    virtual const char *NAME()
    {
        return "Mandelbrot__3";
    }
    unsigned char RD(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + j * 8e-9 - .645411;
            a = c - d + i * 8e-9 + .356888;
        }
        return 2000 * pow((n) / 800, .5);
    }
    unsigned char GR(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + j * 8e-9 - .645411;
            a = c - d + i * 8e-9 + .356888;
        }
        return 1000 * pow((n) / 800, .5);
    }
    unsigned char BL(int i, int j)
    {
        double a = 0, b = 0, c, d, n = 0;
        while ((c = a * a) + (d = b * b) < 4 && n++ < 880)
        {
            b = 2 * a * b + j * 8e-9 - .645411;
            a = c - d + i * 8e-9 + .356888;
        }
        return 4000 * pow((n) / 800, .5);
    }
};

class Mandelbrot__4 : public painter
{
    virtual const char *NAME()
    {
        return "Mandelbrot__4";
    }
    unsigned char RD(int i, int j)
    {
        double r = i / 256. - 2, s = j / 256. - 2, q = r * r + s * s, n = hypot(r + (.866 - r / 2) / q, s + (r * .866 + s / 2) / q), d = .5 / log(n);
        if (d < 0 || d > 1)
            d = 1;
        return d * (sin(n * 10) * 511 + 512);
    }
    unsigned char GR(int i, int j)
    {
        return 0;
    }
    unsigned char BL(int i, int j)
    {
        double r = i / 256. - 2, s = j / 256. - 2, q = r * r + s * s;
        return RD(i, j) * sqrt(q / 40);
    }
};
/************************************ Julia sets ************************************/

class Julia_Sets_1 : public painter
{
    virtual const char *NAME()
    {
        return "Julia_Sets_1";
    }
    unsigned char RD(int i, int j)
    {
#define D(x) (x - DIM / 2.) / (DIM / 2.)
        float x = D(i), y = D(j), X, Y, n = 0;
        while (n++ < 200 && (X = x * x) + (Y = y * y) < 4)
        {
            x = X - Y + .36237;
            y = 2 * x * y + .32;
        }
        return log(n) * 256;
    }

    unsigned char GR(int i, int j)
    {
        float x = D(i), y = D(j), X, Y, n = 0;
        while (n++ < 200 && (x * x + y * y) < 4)
        {
            X = x;
            Y = y;
            x = X * X - Y * Y + -.7;
            y = 2 * X * Y + .27015;
        }
        return log(n) * 128;
    }

    unsigned char BL(int i, int j)
    {
        float x = D(i), y = D(j), X, Y, n = 0;
        while (n++ < 600 && (x * x + y * y) < 4)
        {
            X = x;
            Y = y;
            x = X * X - Y * Y + .36237;
            y = 2 * X * Y + .32;
        }
        return log(n) * 128;
    }
};

class Julia_Sets_2 : public painter
{
    virtual const char *NAME()
    {
        return "Julia_Sets_2";
    }
    unsigned char RD(int i, int j)
    {
        static int n = 1;
        if (n)
        {
            --n;
            srand(time(0));
        }
#define R rand() / 16384. - 1
#define S                      \
    static float r = R, k = R; \
    float
        return _cb(i ^ j);
    }

    unsigned char GR(int i, int j)
    {
#define D(x) (x - DIM / 2.) / (DIM / 2.),
        S x = D(i) y = D(j) X, Y;
        int n = 0;
        while (n++ < 200 && (X = x) * x + (Y = y) * y < 4)
        {
            x = X * X - Y * Y + r;
            y = 2 * X * Y + k;
        }
        return log(n) * 512;
    }

    unsigned char BL(int i, int j)
    {
        S x = D(i) y = D(j) X, Y;
        int n = 0;
        while (n++ < 200 && (X = x) * x + (Y = y) * y < 4)
        {
            x = X * X - Y * Y + r;
            y = 2 * X * Y + k;
        }
        return log(n) * 512;
    }
};
/************************************ Buddhabrot Antibuddhabrot ************************************/
class Buddhabrot_Antibuddhabrot_1 : public painter
{
    virtual const char *NAME()
    {
        return "Buddhabrot_Antibuddhabrot_1";
    }
    unsigned char RD(int i, int j)
    {
#define f(a, b) for (a = 0; ++a < b;)
#define D float x = 0, y = 0
        static int z, m, n;
        if (!z)
        {
            z = 1;
            f(m, 4096) f(n, 4096) BL(m - 4096, n - 4096);
        };
        return GR(i, j);
    }
    unsigned char GR(int i, int j)
    {
#define R                              \
    a = x * x - y * y + i / 1024. + 2; \
    y = 2 * x * y + j / 1024. + 2
        static float c[DIM][DIM], p;
        if (i >= 0)
            return (p = c[i][j]) > DM1 ? DM1 : p;
        c[j + DIM][i / 2 + DIM] += i % 2 * 2 + 1;
    }
    unsigned char BL(int i, int j)
    {
        D, a, k, p = 0;
        if (i < 0)
            f(k, 5e5)
            {
                R;
                x = a;
                if (x * x > 4 || y * y > 4)
                    break;
                GR(int((x - 2) * 256) * 2 - p, (y - 2) * 256);
                if (!p && k == 5e5 - 1)
                {
                    x = y = k = 0;
                    p = 1;
                }
            }
        else
        {
            return GR(i, j);
        }
    }
};

class Buddhabrot_Antibuddhabrot_2 : public painter
{
    virtual const char *NAME()
    {
        return "Buddhabrot_Antibuddhabrot_2";
    }
    unsigned char RD(int i, int j)
    {
#define f(a) for (a = 0; ++a < DIM;)
        static int z;
        float x = 0, y = 0, m, n, k;
        if (!z)
        {
            z = 1;
            f(m) f(n) GR(m - DIM, n - DIM);
        };
        return BL(i, j);
    }
    unsigned char GR(int i, int j)
    {
        float x = 0, y = 0, a, k;
        if (i < 0)
            f(k)
            {
                a = x * x - y * y + (i + 256.0) / 512;
                y = 2 * x * y + (j + 512.0) / 512;
                x = a;
                if (x * x + y * y > 4)
                    break;
                BL((x - .6) * 512, (y - 1) * 512);
            }
        return BL(i, j);
    }
    unsigned char BL(int i, int j)
    {
        static float c[DIM][DIM];
        if (i < 0 && i > -DIM - 1 && j < 0 && j > -DIM - 1)
            c[j + DIM][i + DIM]++;
        else if (i > 0 && i < DIM && j > 0 && j < DIM)
            return log(c[i][j]) * 110;
    }
};

/************************************ Sierpinski Pentagon ************************************/
class Sierpinski_Pentagon : public painter
{
    virtual const char *NAME()
    {
        return "Sierpinski_Pentagon";
    }
    unsigned char RD(int i, int j)
    {
#define A int x = 0, y = 0, p[10] = { 512, 9, 0, 381, 196, 981, 827, 981, DM1, 381 }
        auto s = 99. / (j + 99);
        return GR(i, j) ? 0 : abs(53 - int((3e3 - i) * s + j * s) % 107);
    }

    unsigned char GR(int i, int j)
    {
        static int c[DIM][DIM];
        if (i + j < 1)
        {
            A;
            for (int n = 0; n < 2e7; n++)
            {
                int v = (rand() % 11 + 1) % 5 * 2;
                x += p[v];
                x /= 2;
                y += p[v + 1];
                y /= 2;
                c[x][y]++;
            }
        }
        return c[i][j];
    }

    unsigned char BL(int i, int j)
    {
        static int c[DIM][DIM];
        if (i + j < 1)
        {
            A;
            for (int n = 0; n < 3e7; n++)
            {
                int v = (rand() % 11 + 4) % 5 * 2;
                x += p[v];
                x /= 2;
                y += p[v + 1];
                y /= 2;
                c[x][y]++;
            }
        }
        return c[i][j];
    }
};
/************************************ Sheet Music ************************************/
class Sheet_Music : public painter
{
    virtual const char *NAME()
    {
        return "Sheet_Music";
    }
    unsigned char RD(int i, int j)
    {
        return ((int)(100 * sin((i + 400) * (j + 100) / 11115.0))) & i;
    }
    unsigned char GR(int i, int j)
    {
        return RD(i, j);
    }
    unsigned char BL(int i, int j)
    {
        return RD(i, j);
    }
};

/************************************ Random Voronoi diagram generator ************************************/
class Random_Voronoi_diagram_1 : public painter
{
    virtual const char *NAME()
    {
        return "Random_Voronoi_diagram_1";
    }
    unsigned char RD(int i, int j)
    {
        int t[64], k = 0, l, e, d = 2e7;
        srand(time(0));
        while (k < 64)
        {
            t[k] = rand() % DIM;
            if ((e = _sq(i - t[k]) + _sq(j - t[42 & k++])) < d)
                d = e, l = k;
        }
        return t[l];
    }

    unsigned char GR(int i, int j)
    {
        static int t[64];
        int k = 0, l, e, d = 2e7;
        while (k < 64)
        {
            if (!t[k])
                t[k] = rand() % DIM;
            if ((e = _sq(i - t[k]) + _sq(j - t[42 & k++])) < d)
                d = e, l = k;
        }
        return t[l];
    }

    unsigned char BL(int i, int j)
    {
        static int t[64];
        int k = 0, l, e, d = 2e7;
        while (k < 64)
        {
            if (!t[k])
                t[k] = rand() % DIM;
            if ((e = _sq(i - t[k]) + _sq(j - t[42 & k++])) < d)
                d = e, l = k;
        }
        return t[l];
    }
};

class Random_Voronoi_diagram_2 : public painter
{
    virtual const char *NAME()
    {
        return "Random_Voronoi_diagram_2";
    }
    unsigned char RD(int i, int j)
    {
        int t[64],    // table of 64 points's x coordinate
            k = 0,    // used for loops
            l,        // retains the index of the nearest point
            e,        // for intermediary results
            d = 2e7;  // d is the minimum distance to the (i,j) pixel encoutnered so far
        // it is initially set to 2e7=2'000'000 to be greater than the maximum distance 1024²

        srand(time(0));  // seed for random based on time of run
        // if the run overlaps two seconds, a split will be observed on the red diagram but that is
        // the better compromise I found

        while (k < 64)  // for every point
        {
            t[k] = rand() % DIM;  // assign it a random x coordinate in [0, 1023] range
            // this is done at each call unfortunately because static keyword and srand(...)
            // were mutually exclusive, lenght-wise

            if ((e =                     // assign the distance between pixel (i,j) and point of index k
                 _sq(i - t[k])           // first part of the euclidian distance
                 + _sq(j - t[42 & k++])  // second part, but this is the trick to have "" random "" y coordinates
                 // instead of having another table to generate and look at, this uses the x coordinate of another point
                 // 42 is 101010 in binary, which is a better pattern to apply a & on; it doesn't use all the table
                 // I could have used 42^k to have a bijection k <-> 42^k but this creates a very visible pattern splitting the image at the diagonal
                 // this also post-increments k for the while loop
                 )
                < d  // chekcs if the distance we just calculated is lower than the minimal one we knew
            )
                // {                            // if that is the case
                d = e,      // update the minimal distance
                    l = k;  // retain the index of the point for this distance
                            // the comma ',' here is a trick to have multiple expressions in a single statement
                            // and therefore avoiding the curly braces for the if
            // }
        }

        return t[l];  // finally, return the x coordinate of the nearest point
        // wait, what ? well, the different areas around points need to have a
        // "" random "" color too, and this does the trick without adding any variables
    }

    // The general idea is the same so I will only comment the differences from GR
    unsigned char GR(int i, int j)
    {
        static int t[64];  // we don't need to bother a srand() call, so we can have these points
        // static and generate their coordinates only once without adding too much characters
        // in C++, objects with static storage are initialized to 0
        // the table is therefore filled with 60 zeros
        // see http://stackoverflow.com/a/201116/1119972

        int k = 0, l, e, d = 2e7;

        while (k < 64)
        {
            if (!t[k])                // this checks if the value at index k is equal to 0 or not
                                      // the negation of 0 will cast to true, and any other number to false
                t[k] = rand() % DIM;  // assign it a random x coordinate

            // the following is identical to RD
            if ((e = _sq(i - t[k]) + _sq(j - t[42 & k++])) < d)
                d = e, l = k;
        }

        return t[l];
    }
    unsigned char BL(int i, int j)
    {
        static int t[64];
        int k = 0, l, e, d = 2e7;
        while (k < 64)
        {
            if (!t[k])
                t[k] = rand() % DIM;
            if ((e = _sq(i - t[k]) + _sq(j - t[42 & k++])) < d)
                d = e, l = k;
        }
        return t[l];
    }
};
/************************************ Lyapunov Fractal ************************************/
class Lyapunov_Fractal_1 : public painter
{
    virtual const char *NAME()
    {
        return "Lyapunov_Fractal_1";
    }
    unsigned char RD(int i, int j)
    {
        float r, s = 0, x = .5;
        for (int k = 0; k++ < 50;)
            r = k % 5 == 2 || k % 5 == 4 ? (2. * j) / DIM + 2 : (2. * i) / DIM + 2, x *= r * (1 - x), s += log(fabs(r - r * 2 * x));
        return abs(s);
    }

    unsigned char GR(int i, int j)
    {
        float r, s = 0, x = .5;
        for (int k = 0; k++ < 50;)
            r = k % 5 == 2 || k % 5 == 4 ? (2. * j) / DIM + 2 : (2. * i) / DIM + 2, x *= r * (1 - x), s += log(fabs(r - r * 2 * x));
        return s > 0 ? s : 0;
    }

    unsigned char BL(int i, int j)
    {
        float r, s = 0, x = .5;
        for (int k = 0; k++ < 50;)
            r = k % 5 == 2 || k % 5 == 4 ? (2. * j) / DIM + 2 : (2. * i) / DIM + 2, x *= r * (1 - x), s += log(fabs(r - r * 2 * x));
        return abs(s * x);
    }
};

class Lyapunov_Fractal_2 : public painter
{
    virtual const char *NAME()
    {
        return "Lyapunov_Fractal_2";
    }
    unsigned char RD(int i, int j)
    {
        float x = 0, y = 0;
        for (int k = 0; k++ < 15;)
        {
            float t = _sq(sin(x)) - _sq(cos(y)) + (i - 512.) / 512;
            y = 2 * sin(x) * cos(y) + (j - 512.0) / 512;
            x = t;
        }
        return 2.5 * (x * x + y * y);
    }

    // The general idea is the same so I will only comment the differences from GR
    unsigned char GR(int i, int j)
    {
        float x = 0, y = 0;
        for (int k = 0; k++ < 15;)
        {
            float t = _sq(sin(x)) - _sq(cos(y)) + (i - 512.) / 512;
            y = 2 * sin(x) * cos(y) + (j - 512.0) / 512;
            x = t;
        }
        return 15 * fabs(x);
    }
    unsigned char BL(int i, int j)
    {
        float x = 0, y = 0;
        for (int k = 0; k++ < 15;)
        {
            float t = _sq(sin(x)) - _sq(cos(y)) + (i - 512.) / 512;
            y = 2 * sin(x) * cos(y) + (j - 512.0) / 512;
            x = t;
        }
        return 15 * fabs(y);
    }
};
/************************************ Because unicorns ************************************/
class Because_Unicorns : public painter
{
    virtual const char *NAME()
    {
        return "Because_Unicorns";
    }
    unsigned char RD(int i, int j)
    {
        return (char)(_sq(cos(atan2(j - 512, i - 512) / 2)) * 255);
    }
    unsigned char GR(int i, int j)
    {
        return (char)(_sq(cos(atan2(j - 512, i - 512) / 2 - 2 * acos(-1) / 3)) * 255);
    }
    unsigned char BL(int i, int j)
    {
        return (char)(_sq(cos(atan2(j - 512, i - 512) / 2 + 2 * acos(-1) / 3)) * 255);
    }
};

/************************************ Logistic Hills ************************************/
class Logistic_Hills : public painter
{
    virtual const char *NAME()
    {
        return "Logistic_Hills";
    }
    unsigned char RD(int i, int j)
    {
#define A float a = 0, b, k, r, x
#define B int e, o
#define C(x) x > 255 ? 255 : x
#define R return
#define D DIM
        R BL(i, j) * (D - i) / D;
    }
    unsigned char GR(int i, int j)
    {
#define E DM1
#define F static float
#define G for(
#define H                  \
    r = a * 1.6 / D + 2.4; \
    x = 1.0001 * b / D
        R BL(i, j) * (D - j / 2) / D;
    }
    unsigned char BL(int i, int j)
    {
        F c[D][D];
        if (i + j < 1)
        {
            A;
            B;
            G;
            a < D;a+=0.1)
            {
                G b = 0;
                b < D;b++)
                {
                    H;
                    G k = 0;
                    k < D;k++)
                    {
                        x = r * x * (1 - x);
                        if (k > D / 2)
                        {
                            e = a;
                            o = (E * x);
                            c[e][o] += 0.01;
                        }
                    }
                }
            }
        }
        R C(c[j][i]) * i / D;
    }
};

/************************************ Diffusion Limited Aggregation ************************************/
class Diffusion_Limited_Aggregation_1 : public painter
{
    virtual const char *NAME()
    {
        return "Diffusion_Limited_Aggregation_1";
    }
    unsigned char RD(int i, int j)
    {
#define D DIM
#define M m[(x + D + (d == 0) - (d == 2)) % D][(y + D + (d == 1) - (d == 3)) % D]
#define R rand() % D
#define B m[x][y]
        return (i + j) ? 256 - (BL(i, j)) / 2 : 0;
    }

    unsigned char GR(int i, int j)
    {
#define A                                                          \
    static int m[D][D], e, x, y, d, c[4], f, n;                    \
    if (i + j < 1)                                                 \
    {                                                              \
        for (d = D * D; d; d--)                                    \
        {                                                          \
            m[d % D][d / D] = d % 6 ? 0 : rand() % 2000 ? 1 : 255; \
        }for(n=1
        return RD(i, j);
    }

    unsigned char BL(int i, int j)
    {
        A;
        n;n++)
        {
            x = R;
            y = R;
            if (B == 1)
            {
                f = 1;
                for (d = 0; d < 4; d++)
                {
                    c[d] = M;
                    f = f < c[d] ? c[d] : f;
                }
                if (f > 2)
                {
                    B = f - 1;
                }
                else
                {
                    ++e %= 4;
                    d = e;
                    if (!c[e])
                    {
                        B = 0;
                        M = 1;
                    }
                }
            }
        }
    }
    return m[i][j];
}
}
;
class Diffusion_Limited_Aggregation_2 : public painter
{
    virtual const char *NAME()
    {
        return "Diffusion_Limited_Aggregation_2";
    }
    unsigned char RD(int i, int j)
    {
#define D DIM
#define M m[(x + D + (d == 0) - (d == 2)) % D][(y + D + (d == 1) - (d == 3)) % D]
#define R rand() % D
#define B m[x][y]
        return (i + j) ? 256 - BL(i, j) : 0;
    }

    unsigned char GR(int i, int j)
    {
#define A                                                          \
    static int m[D][D], e, x, y, d, c[4], f, n;                    \
    if (i + j < 1)                                                 \
    {                                                              \
        for (d = D * D; d; d--)                                    \
        {                                                          \
            m[d % D][d / D] = d % 6 ? 0 : rand() % 2000 ? 1 : 255; \
        }for(n=1
        return RD(i, j);
    }

    unsigned char BL(int i, int j)
    {
        A;
        n;n++)
        {
            x = R;
            y = R;
            if (B == 1)
            {
                f = 1;
                for (d = 0; d < 4; d++)
                {
                    c[d] = M;
                    f = f < c[d] ? c[d] : f;
                }
                if (f > 2)
                {
                    B = f - 1;
                }
                else
                {
                    ++e %= 4;
                    d = e;
                    if (!c[e])
                    {
                        B = 0;
                        M = 1;
                    }
                }
            }
        }
    }
    return m[i][j];
}
}
;

/************************************ Spiral ************************************/
class Spiral_1 : public painter
{
    virtual const char *NAME()
    {
        return "Spiral_1";
    }
    unsigned char RD(int i, int j)
    {
        return DIM - BL(2 * i, 2 * j);
    }
    unsigned char GR(int i, int j)
    {
        return BL(j, i) + 128;
    }
    unsigned char BL(int i, int j)
    {
        i -= 512;
        j -= 512;
        int d = sqrt(i * i + j * j);
        return d + atan2(j, i) * 82 + sin(_cr(d * d)) * 32 + sin(atan2(j, i) * 10) * 64;
    }
};

class Spiral_2 : public painter
{
    virtual const char *NAME()
    {
        return "Spiral_2";
    }
    unsigned char RD(int i, int j)
    {
        // *2 expand the spiral
        // DIM- reverse the gradient
        return DIM - BL(2 * i, 2 * j);
    }
    unsigned char GR(int i, int j)
    {
        // notice swapped parameters
        // 128 changes phase of the spiral
        return BL(j, i) + 128;
    }
    unsigned char BL(int i, int j)
    {
        // center it
        i -= DIM / 2;
        j -= DIM / 2;

        double theta = atan2(j, i);         // angle that point is from center
        double prc = theta / 3.14f / 2.0f;  // percent around the circle

        int dist = sqrt(i * i + j * j);  // distance from center

        // EDIT: if you change this to something like "prc * n * 256" where n
        //   is an integer, the spirals will line up for any arbitrarily sized
        //   DIM value, or if you make separate DIMX and DIMY values!
        int makeSpiral = prc * DIM / 2;

        // makes pattern on edge of the spiral
        int waves = sin(_cr(dist * dist)) * 32 + sin(theta * 10) * 64;

        return dist + makeSpiral + waves;
    }
};

/************************************ Reflected waves ************************************/
class Reflected_Waves : public painter
{
    virtual const char *NAME()
    {
        return "Reflected_Waves";
    }

    unsigned char RD(int i, int j)
    {
#define A                                                 \
    static double w = 8000, l, k, r, d, p, q, a, b, x, y; \
    x = i;                                                \
    y = j;                                                \
    for (a = 8; a + 9; a--)                               \
    {                                                     \
        for (b = 8; b + 9; b--)                           \
        {                                                 \
            l = i - a * DIM - (int(a) % 2 ? 227 : 796);
        return 0;
    }

    unsigned char GR(int i, int j)
    {
#define B                                               \
    k = j - b * DIM - (int(b) % 2 ? 417 : 606);         \
    r = sqrt(l * l + k * k);                            \
    d = 16 * cos((r - w) / 7) * exp(-_sq(r - w) / 120); \
    p = d * l / r;                                      \
    q = d * k / r;                                      \
    x -= p;                                             \
    y -= q;                                             \
    }                                                   \
    }
        return 0;
    }

    unsigned char BL(int i, int j)
    {
        A;
        B;
        return (int(x / 64) + int(y / 64)) % 2 * 255;
    }
};
/************************************ groovy ************************************/
class groovy : public painter
{
    virtual const char *NAME()
    {
        return "groovy";
    }

    unsigned char RD(int i, int j)
    {
#define I (i - 512)
#define J (j - 512)
#define A (sin((i + j) / 64.) * cos((i - j) / 64.))
        return atan2(I * cos A - J * sin A, I * sin A + J * cos A) / M_PI * 1024 + 1024;
    }

    unsigned char GR(int i, int j)
    {
#undef A
#define A (M_PI / 3 + sin((i + j) / 64.) * cos((i - j) / 64.))
        return atan2(I * cos A - J * sin A, I * sin A + J * cos A) / M_PI * 1024 + 1024;
    }

    unsigned char BL(int i, int j)
    {
#undef A
#define A (2 * M_PI / 3 + sin((i + j) / 64.) * cos((i - j) / 64.))
        return atan2(I * cos A - J * sin A, I * sin A + J * cos A) / M_PI * 1024 + 1024;
    }
};

/************************************ Sierpinski Paint Splash ************************************/
class Sierpinski_Paint_Splash : public painter
{
    virtual const char *NAME()
    {
        return "Sierpinski_Paint_Splash";
    }

    unsigned char RD(int i, int j)
    {
        return (sqrt(_sq(abs(73. - i)) + _sq(abs(609. - j))) + 1.) / abs(sin((sqrt(_sq(abs(860. - i)) + _sq(abs(162. - j)))) / 115.) + 2)
               / (115 ^ i & j);
    }
    unsigned char GR(int i, int j)
    {
        return (sqrt(_sq(abs(160. - i)) + _sq(abs(60. - j))) + 1.) / abs(sin((sqrt(_sq(abs(73. - i)) + _sq(abs(609. - j)))) / 115.) + 2)
               / (115 ^ i & j);
    }
    unsigned char BL(int i, int j)
    {
        return (sqrt(_sq(abs(600. - i)) + _sq(abs(259. - j))) + 1.) / abs(sin((sqrt(_sq(abs(250. - i)) + _sq(abs(20. - j)))) / 115.) + 2)
               / (115 ^ i & j);
    }
};

/************************************ simple ************************************/
class simple : public painter
{
    virtual const char *NAME()
    {
        return "simple";
    }

    unsigned char RD(int i, int j)
    {
        return j ^ j - i ^ i;
    }
    unsigned char GR(int i, int j)
    {
        return (i - DIM) ^ 2 + (j - DIM) ^ 2;
    }
    unsigned char BL(int i, int j)
    {
        return i ^ i - j ^ j;
    }
};

/************************************ coloured vinyl ************************************/
class coloured_vinyl_1 : public painter
{
    virtual const char *NAME()
    {
        return "coloured_vinyl_1";
    }

    unsigned char RD(int i, int j)
    {
        static int h[1000];
        return j < 0 ? h[i] ? h[i] : h[i] = i < 2 ? 1 : RD(i - RD(i - 1, j), j) + RD(i - RD(i - 2, j), j) : GR(i + 256, j + 512);
    }
    unsigned char GR(int i, int j)
    {
        return DIM - 4 * RD(sqrt((i - 512) * (i - 512) + (j - 768) * (j - 768)) / 2.9, -1);
    }
    unsigned char BL(int i, int j)
    {
        return DIM - 4 * RD(sqrt((i - 768) * (i - 768) + (j - 256) * (j - 256)) / 2.9, -1);
    }
};

class coloured_vinyl_2 : public painter
{
    virtual const char *NAME()
    {
        return "coloured_vinyl_2";
    }

    unsigned char RD(int i, int j)
    {
        static int h[1024];
        return j < 0 ? h[i] ? h[i] : h[i] = i < 2 ? 1 : RD(i - RD(i - 1, j), j) + RD(i - RD(i - 2, j), j) :
                       RD(2 * RD(i, -1) - i + 512 > 1023 - j ? i : 1023 - i, -1) / 0.6;
    }
    unsigned char GR(int i, int j)
    {
        return RD(i, j);
    }
    unsigned char BL(int i, int j)
    {
        return RD(i, j);
    }
};

/************************************ Tribute to a classic ************************************/
class Tribute_to_a_classic_1 : public painter
{
    virtual const char *NAME()
    {
        return "Tribute_to_a_classic_1";
    }

    unsigned char RD(int i, int j)
    {
// RED
#define g(I, S, W, M) j / 128 % 8 == I &W >> (j / 32 % 4 * 16 + i / 64) % M &S[abs(i / 4 % 16 - 8) - (I % 2 & i % 64 < 32)] >> j / 4 % 8 & 1
        return g(1, "_\xB6\\\x98\0\0\0", 255L << 36, 64) ? j : 0;
    }
    unsigned char GR(int i, int j)
    {
        // GREEN
#define S g(6, "\xFF\xFE\xF8\xF8\xF8\xF8\xF0\x0", 1L << 22, 64) | i / 4 == 104 & j / 24 == 30
        return g(2, "<\xBC\xB6}\30p\0\0", 4080, 32) | S ? j : 0;
    }
    unsigned char BL(int i, int j)
    {
        // BLUE
        return g(3, "_7\xB6\xFE\x5E\34\0", 0x70000000FD0, 64) | S | abs(i / 4 - 128) == 80 & abs(j / 4 - 128) < 96
                       | abs(j / 4 - 128) == 96 & abs(i / 4 - 128) < 80 ?
                   j :
                   0;
    }
};

class Tribute_to_a_classic_2 : public painter
{
    virtual const char *NAME()
    {
        return "Tribute_to_a_classic_2";
    }
    unsigned char RD(int i, int j)
    {
// RED
#define g(S) (S[i / 29 % 18 * 2 + j / 29 / 8 % 2] >> j / 29 % 8 & 1) * DM1 *(abs(i - 512) < 247 & abs(j - 464) < 232)
        return g("\xF3\xF2\xF2\x10\xF4\0\xF2\x10\xE1\xE0\x81\0\x80\0\x80\0\0\0\0\0@\0! \x03d8,=\x2C\x99\x84\xC3\x82\xE1\xE3");
    }
    unsigned char GR(int i, int j)
    {
        // GREEN
        return g(";\376z\34\377\374\372\30k\360\3\200\0\0\0\0\0\0\200\0\300\0\341 \373d\307\354\303\374e\374;\376;\377") ? DM1 :
                                                                                                                           BL(i, j) ? DM1 / 2 : 0;
    }
    unsigned char BL(int i, int j)
    {
        // BLUE
        return g("\363\360\362\20\364\0\362\20\341\340\200\0\200\0\200\0\0\0\0\0\0\0\0\0\0\08\0<\0\230\0\300\0\341\340") / 2;
    }
};

/************************************ Tribute to a classic ************************************/
class Action_Painting_1 : public painter
{
    virtual const char *NAME()
    {
        return "Action_Painting_1";
    }

    unsigned char RD(int i, int j)
    {
#define E(q) return i + j ? T - ((T - BL(i, j)) * q) : T;
#define T 255
#define R .1 * (rand() % 11)
#define M(v) (v > 0 & v < DIM) * int(v)
#define J [j] * 250;
        E(21)
    }

    unsigned char GR(int i, int j)
    {
#define S DIM][DIM],n=1e3,r,a,s,c,x,y,d=.1,e,f; \
    for (; i + j < 1 && n--; x = R * DM1, y = R * DM1, s = R * R * R * R, a = R * 7, r = s * T)for(c=R;r>1;x+=s*cos(a),y+=s*sin
        E(21)
    }

    unsigned char BL(int i, int j)
    {static float m[S(a),d=rand()%39?d:-d,a+=d*R,s*=1+R/99,r*=.998)for(e=-r;e++<r;)for(f=-r;f++<r;)m[M(x+e)*(e*e+f*f<r)][M(y+f)]=c;return T-m[i]J
    }
};

/************************************ painter vector ************************************/

using painter_ptr = std::shared_ptr<painter>;
static std::vector<painter_ptr> paintervec = {nullptr};
std::vector<painter_ptr> &getPainterPtr()
{
    paintervec.push_back(std::make_shared<Table_Cloths_Flat>());
    paintervec.push_back(std::make_shared<Table_Cloths_Ripple>());
    paintervec.push_back(std::make_shared<Table_Cloths_Colour>());
    paintervec.push_back(std::make_shared<Table_Cloths_motion>());

    paintervec.push_back(std::make_shared<Random>());

    paintervec.push_back(std::make_shared<Swirly_1>());
    paintervec.push_back(std::make_shared<Swirly_2>());

    paintervec.push_back(std::make_shared<Mandelbrot_3_133>());
    paintervec.push_back(std::make_shared<Mandelbrot_132>());
    paintervec.push_back(std::make_shared<Mandelbrot__1>());
    paintervec.push_back(std::make_shared<Mandelbrot__1_1>());
    paintervec.push_back(std::make_shared<Mandelbrot__2>());
    paintervec.push_back(std::make_shared<Mandelbrot__3>());
    paintervec.push_back(std::make_shared<Mandelbrot__4>());

    paintervec.push_back(std::make_shared<Julia_Sets_1>());
    paintervec.push_back(std::make_shared<Julia_Sets_2>());

    // paintervec.push_back(std::make_shared<Buddhabrot_Antibuddhabrot_1>());
    paintervec.push_back(std::make_shared<Buddhabrot_Antibuddhabrot_2>());

    paintervec.push_back(std::make_shared<Sierpinski_Pentagon>());

    paintervec.push_back(std::make_shared<Sheet_Music>());

    paintervec.push_back(std::make_shared<Random_Voronoi_diagram_1>());
    paintervec.push_back(std::make_shared<Random_Voronoi_diagram_2>());

    paintervec.push_back(std::make_shared<Lyapunov_Fractal_1>());
    paintervec.push_back(std::make_shared<Lyapunov_Fractal_2>());

    paintervec.push_back(std::make_shared<Because_Unicorns>());

    // paintervec.push_back(std::make_shared<Logistic_Hills>());

    // paintervec.push_back(std::make_shared<Diffusion_Limited_Aggregation_1>());
    paintervec.push_back(std::make_shared<Diffusion_Limited_Aggregation_2>());

    paintervec.push_back(std::make_shared<Spiral_1>());
    paintervec.push_back(std::make_shared<Spiral_2>());

    paintervec.push_back(std::make_shared<Reflected_Waves>());

    paintervec.push_back(std::make_shared<groovy>());

    paintervec.push_back(std::make_shared<Sierpinski_Paint_Splash>());

    paintervec.push_back(std::make_shared<simple>());

    paintervec.push_back(std::make_shared<coloured_vinyl_1>());
    // paintervec.push_back(std::make_shared<coloured_vinyl_2>());

    paintervec.push_back(std::make_shared<Tribute_to_a_classic_1>());
    paintervec.push_back(std::make_shared<Tribute_to_a_classic_2>());

    paintervec.push_back(std::make_shared<Action_Painting_1>());

    return paintervec;
}
